<template>
  <div class="json-formatter">


    <!-- 主内容区 -->
    <div class="tool-container">
      <!-- 左侧JSON编辑器面板 -->
      <div class="editor-panel">
        <div class="panel-header">
          <h2 class="panel-title">
            <i class="fa fa-file-code-o"></i>
            JSON文本
          </h2>
          <div class="panel-actions">
            <button @click="formatJson" class="action-btn format-btn">
              <i class="fa fa-indent"></i>
              <span>格式化</span>
            </button>
            <button @click="compressJson" class="action-btn compress-btn">
              <i class="fa fa-compress"></i>
              <span>压缩</span>
            </button>
            <button @click="copyJson" class="action-btn copy-btn">
              <i class="fa fa-copy"></i>
              <span>复制</span>
            </button>
            <button @click="clearJson" class="action-btn clear-btn">
              <i class="fa fa-trash"></i>
              <span>清空</span>
            </button>
          </div>
          <div class="json-status" :class="{ 'valid': jsonValid, 'invalid': !jsonValid }">
            <i class="fa" :class="jsonValid ? 'fa-check-circle' : 'fa-exclamation-circle'"></i>
            {{ jsonValid ? '有效' : '格式错误' }}
          </div>
        </div>
        
        <div class="editor-wrapper">
          <codemirror
            v-model="jsonText"
            :options="editorOptions"
            @input="updateJson"
            @scroll="syncLineNumbers"
            class="json-editor-cm"
            placeholder="请输入JSON数据..."
          />
        </div>
      </div>

      <!-- 拖拽分割线 -->
      <div class="resizer" @mousedown="startResize"></div>

      <!-- 右侧树结构面板 -->
      <div class="tree-panel">
        <div class="panel-header">
          <h2 class="panel-title">
            <i class="fa fa-sitemap"></i>
            树状结构
          </h2>
          <div class="panel-actions">
            <button @click="toggleExpandAll" class="action-btn expand-btn">
              <i class="fa" :class="allExpanded ? 'fa-minus-square-o' : 'fa-plus-square-o'"></i>
              <span>{{ allExpanded ? '全部折叠' : '全部展开' }}</span>
            </button>
          </div>
        </div>
        
        <div class="tree-view">
          <div v-if="!jsonData" class="empty-state">
            <i class="fa fa-file-text-o"></i>
            <p>输入JSON数据后，这里将显示对应的树状结构</p>
            <p class="hint">支持实时编辑和双向同步，严格保持节点原有顺序</p>
          </div>
          <json-tree 
            v-else 
            :data="jsonData" 
            :expanded="allExpanded"
            @update="handleTreeUpdate"></json-tree>
        </div>
      </div>
    </div>

    <!-- 底部状态栏 -->
    <footer class="status-bar">
      <div class="status-info">
        <span class="node-count">{{ nodeCount }} 个节点</span>
        <span class="char-count">{{ charCount }} 个字符</span>
        <span v-if="error" class="error-info">{{ error.message }}</span>
      </div>
    </footer>
  </div>
</template>

<script>
import JsonTree from '../../components/JsonTree.vue'
import { Codemirror } from 'vue-codemirror'


export default {
  name: 'JsonFormat',
  components: {
    JsonTree,
    Codemirror
  },
  data() {
    return {
      jsonText: '',
      jsonData: null,
      jsonValid: false,
      allExpanded: true,
      error: null,
      lineCount: [1],
      nodeCount: 0,
      charCount: 0,
      isResizing: false,
      leftPanelWidth: '50%',
      isSyncingScroll: false,
      scrollSyncTimer: null,
      isScrolling: false,
      editorOptions: {
        lineNumbers: true,
        lineWrapping: true,
        indentUnit: 2,
        tabSize: 2,
        smartIndent: true,
        matchBrackets: true,
        autoCloseBrackets: true,
        styleActiveLine: true,
        showCursorWhenSelecting: true,
        extraKeys: {
          'Ctrl-Space': 'autocomplete',
          'Tab': 'indentMore',
          'Shift-Tab': 'indentLess'
        }
      }
    }
  },
  watch: {
    jsonText: {
      handler(newText) {
        this.charCount = newText.length;
        this.updateJson();
      },
      immediate: true
    },
    jsonData: {
      handler(newData) {
        this.nodeCount = this.countNodes(newData);
      },
      immediate: true
    }
  },
  mounted() {
    // 初始化示例数据
    this.initSampleData();
    
    // 添加滚动事件监听
    const editorWrapper = this.$el.querySelector('.editor-wrapper');
    const treeView = this.$el.querySelector('.tree-view');
    if (editorWrapper && treeView) {
      editorWrapper.addEventListener('scroll', this.handleEditorScroll);
      treeView.addEventListener('scroll', this.handleTreeScroll);
    }
  },

  beforeDestroy() {
    // 移除滚动事件监听
    const editorWrapper = this.$el.querySelector('.editor-wrapper');
    const treeView = this.$el.querySelector('.tree-view');
    if (editorWrapper && treeView) {
      editorWrapper.removeEventListener('scroll', this.handleEditorScroll);
      treeView.removeEventListener('scroll', this.handleTreeScroll);
    }
  },
  methods: {
    updateLineNumbers() {
      const lines = this.jsonText.split('\n').length || 1;
      this.lineCount = Array.from({length: lines}, (_, i) => i + 1);
    },
    initSampleData() {
      const sampleData = {
        "name": "JSON树结构转换工具",
        "version": "1.0.0",
        "description": "这是一个功能强大的JSON格式化和树状结构展示工具",
        "features": [
          "实时编辑",
          "双向同步",
          "严格保持顺序",
          "精确错误定位",
          "格式化",
          "压缩"
        ],
        "settings": {
          "theme": "light",
          "autoFormat": true,
          "indentSize": 2,
          "maxDepth": 10,
          "showLineNumbers": true
        },
        "stats": {
          "users": 1500,
          "rating": 4.8,
          "downloads": 8924,
          "isActive": true,
          "isPremium": false
        },
        "numbers": {
          "integer": 42,
          "float": 3.14159,
          "negative": -15,
          "zero": 0,
          "largeNumber": 1000000
        },
        "booleans": {
          "trueValue": true,
          "falseValue": false,
          "mixedArray": [true, false, true, false]
        },
        "strings": {
          "simple": "Hello World",
          "empty": "",
          "withSpaces": "This is a string with spaces",
          "specialChars": "Line1",
          "unicode": "中文测试 🚀"
        },
        "arrays": {
          "emptyArray": [],
          "numberArray": [1, 2, 3, 4, 5],
          "stringArray": ["apple", "banana", "cherry"],
          "mixedArray": [1, "text", true, null],
          "nestedArray": [
            [1, 2, 3],
            ["a", "b", "c"],
            [true, false]
          ]
        },
        "nullValues": {
          "nullValue": null,
          "undefinedValue": null,
          "mixed": [null, "not null", null]
        },
        "complex": {
          "deepObject": {
            "level1": {
              "level2": {
                "level3": {
                  "finalValue": "Deep nesting example"
                }
              }
            }
          },
          "mixedTypes": {
            "number": 123,
            "string": "abc",
            "boolean": true,
            "array": [1, 2, 3],
            "object": {
              "nested": "value"
            }
          }
        }
      };
      
      this.jsonText = JSON.stringify(sampleData, null, 2);
      this.updateJson();
    },
    countNodes(data) {
      if (!data) return 0;
      
      let count = 0;
      const traverse = (obj) => {
        count++;
        if (typeof obj === 'object' && obj !== null) {
          if (Array.isArray(obj)) {
            obj.forEach(item => traverse(item));
          } else {
            Object.values(obj).forEach(value => traverse(value));
          }
        }
      };
      
      traverse(data);
      return count;
    },
    updateJson() {
      try {
        this.jsonData = JSON.parse(this.jsonText);
        this.jsonValid = true;
        this.error = null;
        this.nodeCount = this.countNodes(this.jsonData);
      } catch (e) {
        this.jsonValid = false;
        this.error = this.parseError(e);
        // 解析错误时不清空数据，保留原数据
        if (!this.jsonData) {
          try {
            // 尝试解析部分数据作为预览
            const partialText = this.jsonText.substring(0, Math.min(this.jsonText.length, 1000));
            this.jsonData = JSON.parse(partialText + '...');
          } catch {
            // 如果部分解析也失败，保持当前数据不变
          }
        }
      }
      this.updateLineNumbers();
    },
    formatJson() {
      if (!this.jsonValid) return;
      this.jsonText = JSON.stringify(this.jsonData, null, 2);
      this.showNotification('JSON已格式化', 'success');
    },
    compressJson() {
      if (!this.jsonValid) return;
      this.jsonText = JSON.stringify(this.jsonData);
      this.showNotification('JSON已压缩', 'success');
    },
    copyJson() {
      if (!this.jsonText) {
        this.showNotification('没有可复制的内容', 'warning');
        return;
      }
      
      navigator.clipboard.writeText(this.jsonText)
        .then(() => {
          this.showNotification('JSON已复制到剪贴板', 'success');
        })
        .catch(() => {
          this.showNotification('复制失败，请手动复制', 'error');
        });
    },
    clearJson() {
      if (confirm('确定要清空所有内容吗？')) {
        this.jsonText = '';
        this.jsonData = null;
        this.jsonValid = false;
        this.error = null;
        this.nodeCount = 0;
        this.charCount = 0;
        this.showNotification('内容已清空', 'info');
      }
    },
    toggleExpandAll() {
      this.allExpanded = !this.allExpanded
    },
    handleTreeUpdate(newData) {
      this.jsonData = newData;
      this.jsonText = JSON.stringify(newData, null, 2);
      this.updateLineNumbers();
      this.jsonValid = true;
      this.error = null;
      this.nodeCount = this.countNodes(newData);
    },
    parseError(error) {
      const match = error.message.match(/at position (\d+)/)
      const position = match ? parseInt(match[1]) : 0
      const lines = this.jsonText.substring(0, position).split('\n')
      return {
        message: error.message,
        line: lines.length,
        column: lines[lines.length - 1].length + 1
      }
    },
    showNotification(message, type = 'info') {
      // 创建通知元素
      const notification = document.createElement('div');
      notification.className = 'notification';
      
      // 设置样式
      const styles = {
        info: { background: '#3b82f6', icon: 'fa-info-circle' },
        success: { background: '#10b981', icon: 'fa-check-circle' },
        warning: { background: '#f59e0b', icon: 'fa-exclamation-triangle' },
        error: { background: '#ef4444', icon: 'fa-exclamation-circle' }
      };
      
      const style = styles[type] || styles.info;
      
      notification.innerHTML = `
        <i class="fa ${style.icon}"></i>
        <span>${message}</span>
      `;
      
      notification.style.cssText = `
        position: fixed;
        top: 20px;
        right: 20px;
        padding: 12px 16px;
        border-radius: 6px;
        color: white;
        font-weight: 600;
        z-index: 1000;
        display: flex;
        align-items: center;
        gap: 8px;
        background: ${style.background};
        box-shadow: 0 4px 12px rgba(0,0,0,0.15);
        animation: slideIn 0.3s ease-out;
      `;
      
      document.body.appendChild(notification);
      
      // 3秒后自动移除
      setTimeout(() => {
        notification.style.animation = 'slideOut 0.3s ease-in';
        setTimeout(() => {
          if (notification.parentNode) {
            notification.parentNode.removeChild(notification);
          }
        }, 300);
      }, 3000);
    },
    syncLineNumbers() {
      const lineNumbers = this.$el.querySelector('.line-numbers');
      const textarea = this.$el.querySelector('.json-editor');
      if (lineNumbers && textarea) {
        lineNumbers.scrollTop = textarea.scrollTop;
      }
    },

    syncScroll(source, target) {
      if (!this.isSyncingScroll) {
        this.isSyncingScroll = true;
        const sourceEl = this.$el.querySelector(source);
        const targetEl = this.$el.querySelector(target);
        if (sourceEl && targetEl) {
          // 使用更精确的同步方式，避免惯性滚动
          const sourceScrollTop = sourceEl.scrollTop;
          const sourceScrollHeight = sourceEl.scrollHeight;
          const sourceClientHeight = sourceEl.clientHeight;
          
          const targetScrollHeight = targetEl.scrollHeight;
          const targetClientHeight = targetEl.clientHeight;
          
          // 只有当有实际滚动内容时才同步
          if (sourceScrollHeight > sourceClientHeight && targetScrollHeight > targetClientHeight) {
            const percent = sourceScrollTop / (sourceScrollHeight - sourceClientHeight);
            const targetScrollTop = percent * (targetScrollHeight - targetClientHeight);
            
            // 只有当滚动位置有显著变化时才更新
            if (Math.abs(targetEl.scrollTop - targetScrollTop) > 1) {
              targetEl.scrollTop = targetScrollTop;
            }
          }
        }
        this.isSyncingScroll = false;
      }
    },

    handleEditorScroll() {
      // 使用被动事件监听器优化滚动性能
      if (this.scrollSyncTimer) {
        clearTimeout(this.scrollSyncTimer);
      }
      
      // 只在滚动停止后同步，避免惯性滚动
      this.scrollSyncTimer = setTimeout(() => {
        if (!this.isScrolling) {
          this.isScrolling = true;
          requestAnimationFrame(() => {
            this.syncScroll('.editor-wrapper', '.tree-view');
            this.isScrolling = false;
          });
        }
      }, 10); // 10ms延迟确保滚动完全停止
    },

    handleTreeScroll() {
      // 使用被动事件监听器优化滚动性能
      if (this.scrollSyncTimer) {
        clearTimeout(this.scrollSyncTimer);
      }
      
      // 只在滚动停止后同步，避免惯性滚动
      this.scrollSyncTimer = setTimeout(() => {
        if (!this.isScrolling) {
          this.isScrolling = true;
          requestAnimationFrame(() => {
            this.syncScroll('.tree-view', '.editor-wrapper');
            this.isScrolling = false;
          });
        }
      }, 10); // 10ms延迟确保滚动完全停止
    },
    startResize(e) {
      this.isResizing = true;
      document.addEventListener('mousemove', this.handleResize);
      document.addEventListener('mouseup', this.stopResize);
      document.body.style.cursor = 'col-resize';
      document.body.style.userSelect = 'none';
    },
    handleResize(e) {
      if (!this.isResizing) return;
      
      const container = this.$el.querySelector('.tool-container');
      const containerRect = container.getBoundingClientRect();
      const containerWidth = containerRect.width;
      const mouseX = e.clientX;
      const containerLeft = containerRect.left;
      
      const leftWidth = ((mouseX - containerLeft) / containerWidth) * 100;
      const clampedWidth = Math.max(20, Math.min(80, leftWidth));
      
      this.leftPanelWidth = `${clampedWidth}%`;
    },
    stopResize() {
      this.isResizing = false;
      document.removeEventListener('mousemove', this.handleResize);
      document.removeEventListener('mouseup', this.stopResize);
      document.body.style.cursor = '';
      document.body.style.userSelect = '';
    }
  }
}
</script>

<style scoped>
.json-formatter {
  max-width: 1400px;
  margin: 0 auto;
  padding: 0;
  height: calc(100vh - 120px);
  display: flex;
  flex-direction: column;
  background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
}



/* 主容器 */
.tool-container {
  display: flex;
  flex: 1;
  position: relative;
  margin: 0;
  height: calc(100vh - 120px);
}

/* 面板通用样式 */
.editor-panel, .tree-panel {
  display: flex;
  flex-direction: column;
  background: white;
  /* border-radius: 12px; */
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
  overflow: hidden;
  border: 1px solid rgba(255, 255, 255, 0.2);
  backdrop-filter: blur(10px);
}

.editor-panel {
  width: v-bind(leftPanelWidth);
  min-width: 300px;
  max-width: 80%;
  margin-right: 0;
}

.tree-panel {
  flex: 1;
  min-width: 300px;
  margin-left: 0;
  overflow: hidden;
}

/* 拖拽分割线 */
.resizer {
  width: 4px;
  background: #e2e8f0;
  cursor: col-resize;
  position: relative;
  z-index: 10;
  transition: background-color 0.2s ease;
}

.resizer:hover {
  background: #667eea;
}

.resizer::before {
  content: '';
  position: absolute;
  top: 0;
  left: -2px;
  right: -2px;
  bottom: 0;
  background: transparent;
}

/* 面板头部 */
.panel-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 10px 20px;
  background: linear-gradient(135deg, #f8fafc 0%, #e2e8f0 100%);
  border-bottom: 1px solid #e2e8f0;
}

.panel-title {
  font-size: 18px;
  font-weight: 600;
  color: #2d3748;
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0;
}

.panel-title i {
  color: #667eea;
}

.panel-actions {
  display: flex;
  gap: 8px;
}

.action-btn {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 6px 10px;
  border: none;
  border-radius: 8px;
  font-size: 14px;
  font-weight: 500;
  cursor: pointer;
  transition: all 0.3s ease;
  background: white;
  color: #4a5568;
  border: 1px solid #e2e8f0;
}

.action-btn:hover {
  transform: translateY(-1px);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}

.format-btn:hover { background: #4299e1; color: white; border-color: #4299e1; }
.compress-btn:hover { background: #38b2ac; color: white; border-color: #38b2ac; }
.copy-btn:hover { background: #48bb78; color: white; border-color: #48bb78; }
.clear-btn:hover { background: #f56565; color: white; border-color: #f56565; }
.expand-btn:hover { background: #667eea; color: white; border-color: #667eea; }

/* JSON状态指示器 */
.json-status {
  padding: 6px 12px;
  border-radius: 20px;
  font-size: 12px;
  font-weight: 600;
  display: flex;
  align-items: center;
  gap: 6px;
}

.json-status.valid {
  background: #c6f6d5;
  color: #276749;
  border: 1px solid #9ae6b4;
}

.json-status.invalid {
  background: #fed7d7;
  color: #c53030;
  border: 1px solid #fc8181;
}

/* 编辑器区域 */
.editor-wrapper {
  position: relative;
  flex: 1;
  overflow: auto;
  min-height: 400px;
  height: 100%;
}

.json-editor-cm {
  width: 100%;
  height: 100%;
  min-height: 400px;
  font-family: 'Fira Code', 'Menlo', monospace;
  font-size: 14px;
}

/* Codemirror 样式覆盖 */
.json-editor-cm {
  height: 100%;
  min-height: 400px;
}

.json-editor-cm .cm-editor {
  height: 100%;
  min-height: 400px;
  background: #fafafa;
  color: #2d3748;
  font-family: 'Fira Code', 'Menlo', monospace;
  font-size: 14px;
  line-height: 1.5;
}

.json-editor-cm .cm-editor.cm-focused {
  background: white;
  box-shadow: inset 0 0 0 2px #667eea;
}

.json-editor-cm .cm-gutters {
  background: #f7fafc;
  border-right: 1px solid #e2e8f0;
}

.json-editor-cm .cm-lineNumbers .cm-gutterElement {
  color: #a0aec0;
  font-size: 13px;
}

.json-editor-cm .cm-scroller {
  overflow: auto;
  height: 100%;
  min-height: 400px;
  max-height: none;
}

.json-editor-cm .cm-content {
  min-height: 100%;
  padding-bottom: 200px;
}

/* 暗色主题适配 */
[data-theme="dark"] .json-editor-cm .CodeMirror {
  background: #2d3748;
  color: #e8eaed;
}

[data-theme="dark"] .json-editor-cm .CodeMirror-gutters {
  background: #4a5568;
  border-right-color: #718096;
}

[data-theme="dark"] .json-editor-cm .CodeMirror-linenumber {
  color: #a0aec0;
}

/* 树形视图 */
.tree-view {
  flex: 1;
  overflow-x: auto;
  overflow-y: auto;
  padding: 16px;
  background: #fafafa;
  min-width: 0;
  width: 100%;
}

/* 确保树状结构内容可以水平滚动 */
.tree-view > * {
  min-width: 100%;
}

.empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 100%;
  color: #718096;
  text-align: center;
}

.empty-state i {
  font-size: 64px;
  margin-bottom: 20px;
  opacity: 0.4;
}

.empty-state p {
  font-size: 16px;
  margin: 8px 0;
}

.empty-state .hint {
  font-size: 14px;
  color: #a0aec0;
}

/* 底部状态栏 */
.status-bar {
  background: white;
  /* border-radius: 12px; */
  padding: 12px 20px;
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
  border: 1px solid rgba(255, 255, 255, 0.2);
  margin: 0;
}

.status-info {
  display: flex;
  align-items: center;
  gap: 20px;
  font-size: 14px;
  color: #4a5568;
}

.node-count, .char-count {
  padding: 4px 12px;
  background: #edf2f7;
  border-radius: 16px;
  font-weight: 500;
}

.error-info {
  color: #e53e3e;
  font-weight: 500;
  padding: 4px 12px;
  background: #fed7d7;
  border-radius: 16px;
}

/* 动画效果 */
@keyframes pulse {
  0% { opacity: 1; }
  50% { opacity: 0.7; }
  100% { opacity: 1; }
}

@keyframes slideIn {
  from {
    transform: translateX(100%);
    opacity: 0;
  }
  to {
    transform: translateX(0);
    opacity: 1;
  }
}

@keyframes slideOut {
  from {
    transform: translateX(0);
    opacity: 1;
  }
  to {
    transform: translateX(100%);
    opacity: 0;
  }
}

/* 响应式设计 */
@media (max-width: 1024px) {
  .tool-container {
    flex-direction: column;
    height: auto;
  }
  
  .editor-panel, .tree-panel {
    min-height: 400px;
  }
}

.text-primary {
  color: #667eea !important;
}
</style>